GridLayout + Animation 实现 Android 仿超级课程表“发现”全屏宫格图标弹出动画

关于全屏宫格图标,超级课程表的“发现”是目前我见过的最好的解决方案,流畅的动画打破了布局单一带来的死板气氛。下面就来介绍这样的动画是如何实现的。


首先创建一个activity叫BiaoDiscoverActivity

此处用到了Handler,Handler主要用于异步消息的处理:当发出一个消息之后,首先进入一个消息队列,发送消息的函数即刻返回,而另外一个部分在消息队列中逐一将消息取出,然后对消息进行处理,也就是发送消息和接收消息不是同步的处理。 这种机制通常用来处理相对耗时比较长的操作


public class BiaoDiscoverActivity extends BaseActivity {

@Bind(R.id.ivBiaoClose)
ImageView mIvClose;
@Bind(R.id.rll_found_note)
AutoRelativeLayout mrllNote;
@Bind(R.id.rll_found_exam_time)
AutoRelativeLayout mrllExamTime;
@Bind(R.id.rll_found_class_room_search)
AutoRelativeLayout mrllClassroom;
@Bind(R.id.rll_found_score_search)
AutoRelativeLayout mrllScore;
@Bind(R.id.rll_found_super_act)
AutoRelativeLayout mrllSuperAct;
@Bind(R.id.rll_found_super_group)
AutoRelativeLayout mrllSuperGroup;
@Bind(R.id.rll_found_train_tickets)
AutoRelativeLayout mrllTrainTickets;
@Bind(R.id.rll_found_air_tickets)
AutoRelativeLayout mrllAirTickets;
@Bind(R.id.rll_found_school_recuit)
AutoRelativeLayout mrllSchoolRecuit;
@Bind(R.id.rll_found_house_rent)
AutoRelativeLayout mrllHouseRent;
@Bind(R.id.rll_found_entertainment_class)
AutoRelativeLayout mrllEntertainment;

//宫格图标
private List<AutoRelativeLayout> rllList;
private Handler handler;

@Override
protected BasePresenter createPresenter() {
return null;
}

@Override
protected int provideContentViewId() {
return R.layout.activity_biao_discover;
}


@Override
public void initView() {
super.initView();
initRll();
initGrid();
handler = new Handler();
}

private synchronized void initRll() {
rllList = new ArrayList<>();
rllList.add(mrllNote);
rllList.add(mrllExamTime);
rllList.add(mrllClassroom);
rllList.add(mrllScore);
rllList.add(mrllSuperAct);
rllList.add(mrllSuperGroup);
rllList.add(mrllTrainTickets);
rllList.add(mrllAirTickets);
rllList.add(mrllSchoolRecuit);
rllList.add(mrllHouseRent);
rllList.add(mrllEntertainment);
}

@Override
protected void onResume() {
super.onResume();
itemsAnimation();
}

private void initGrid() {
for (int i = 0; i < rllList.size(); i++) {
int finalI = i;
//先全部隐藏
rllList.get(finalI).setVisibility(View.GONE);
}
}

private void itemsAnimation() {
handler.postDelayed(new Runnable() {
@Override
public void run() {
for (int i = 0; i < rllList.size(); i++) {
int finalI = i;
//先全部隐藏
rllList.get(finalI).setAlpha(0);
rllList.get(finalI).setVisibility(View.VISIBLE);
}
for (int i = 0; i < rllList.size(); i++) {
int finalI = i;
handler.postDelayed(new Runnable() {
@Override
public void run() {
//设置透明度为全不透明
rllList.get(finalI).setAlpha(1);
//再执行动画
rllList.get(finalI).startAnimation(AnimationUtils.loadAnimation(BiaoDiscoverActivity.this, R.anim.grid_items_scale));
}
}, 0 + i * 30);
}
}
}, 200);

}

@Override
public void initListener() {
super.initListener();
mIvClose.setOnClickListener(v -> {
finish();
exitAct();
});
mrllClassroom.setOnClickListener(v -> jumpToWebViewActivity(AppConst.H5_CLASSROOM_SEARCH));
mrllScore.setOnClickListener(v -> jumpToWebViewActivity(AppConst.H5_SCORE_RESULT_SEARCH));
mrllSuperGroup.setOnClickListener(v -> jumpToWebViewActivity(AppConst.H5_SUPER_GROUP));
mrllTrainTickets.setOnClickListener(v -> jumpToWebViewActivity(AppConst.H5_TRAIN_BUS_TICKETS));
mrllSchoolRecuit.setOnClickListener(v -> jumpToWebViewActivity(AppConst.H5_SCHOOL_RECUIT));
mrllAirTickets.setOnClickListener(v -> jumpToWebViewActivity(AppConst.H5_AIR_TICKETS));
mrllHouseRent.setOnClickListener(v -> jumpToWebViewActivity(AppConst.H5_HOUSE_RENT));
mrllEntertainment.setOnClickListener(v -> jumpToWebViewActivity(AppConst.H5_ENTERTAINMANIT_CLASS));
}

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
finish();
exitAct();
return true;
}
return super.onKeyDown(keyCode, event);
}

private void exitAct() {
UIUtils.startWindowAnimation(this, R.anim.window_as_pop_fade_in, R.anim.window_as_pop_fade_out);
}
}


其父类为一个抽象类BaseActivity,子类中的各个重写方法在父类中的执行顺序如下


protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(provideContentViewId());
ButterKnife.bind(this);

initView();
initListener();
initData();

}


这样,只需在子类中重写provideContentViewId()方法,返回子类的content布局资源文件的值就可以了,子类不再需要设置布局ID,也不再需要每次调用ButterKnife.bind()


下面是重点

宫格布局的实现

以下是BiaoDiscoverActivity的布局资源文件

首先向 zhy 的 AutoLayout 表示感谢

<?xml version=”1.0” encoding=”utf-8”?>
<com.zhy.autolayout.AutoRelativeLayout
xmlns:android=”http://schemas.android.com/apk/res/android"
android:layout_width=”match_parent”
android:layout_height=”match_parent”>

<com.zhy.autolayout.AutoRelativeLayout
xmlns:android=”http://schemas.android.com/apk/res/android"
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:background=”@drawable/ic_found_bg”
android:paddingBottom=”@dimen/biao_discover_root_padding_bottom”
android:paddingTop=”@dimen/biao_discover_root_padding_top”
>

<include
layout=”@layout/include_toolbar”
android:visibility=”gone”
/>

<GridLayout
android:layout_width=”match_parent”
android:layout_height=”match_parent”
android:layout_alignParentTop=”true”
android:layout_centerHorizontal=”true”
android:layout_gravity=”center_horizontal”
android:columnCount=”3”
android:rowCount=”4”>


<com.zhy.autolayout.AutoRelativeLayout
android:id=”@+id/rll_found_note”
android:layout_width=”wrap_content”
android:layout_column=”0”
android:layout_columnWeight=”1”
android:layout_row=”0”
android:layout_rowWeight=”1”
android:visibility=”visible”
>

<ImageView
android:id=”@+id/imageView3”
android:layout_width=”wrap_content”
android:layout_height=”@dimen/biao_discover_item_iv_height”
android:src=”@drawable/ic_found_note_icon”
android:layout_centerVertical=”true”
android:layout_centerHorizontal=”true”/>

<TextView
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_below=”@+id/imageView3”
android:layout_centerHorizontal=”true”
android:layout_marginTop=”@dimen/biao_discover_item_tv_margin_top”
android:text=”@string/biao_note”
android:textColor=”@color/gray2”
android:textSize=”@dimen/biao_discover_item_tv_text_size”/>
</com.zhy.autolayout.AutoRelativeLayout>


<com.zhy.autolayout.AutoRelativeLayout
android:id=”@+id/rll_found_exam_time”
android:layout_width=”wrap_content”
android:layout_column=”1”
android:layout_columnWeight=”1”
android:layout_row=”0”
android:layout_rowWeight=”1”
android:visibility=”visible”
>

<ImageView
android:id=”@+id/imageView4”
android:layout_width=”wrap_content”
android:layout_height=”@dimen/biao_discover_item_iv_height”
android:src=”@drawable/ic_found_countdown_icon”
android:layout_centerVertical=”true”
android:layout_centerHorizontal=”true”/>

<TextView
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_below=”@+id/imageView4”
android:layout_centerHorizontal=”true”
android:layout_marginTop=”@dimen/biao_discover_item_tv_margin_top”
android:text=”@string/biao_exam_time”
android:textColor=”@color/gray2”
android:textSize=”@dimen/biao_discover_item_tv_text_size”/>
</com.zhy.autolayout.AutoRelativeLayout>

<com.zhy.autolayout.AutoRelativeLayout
android:id=”@+id/rll_found_class_room_search”
android:layout_width=”wrap_content”
android:layout_column=”2”
android:layout_columnWeight=”1”
android:layout_row=”0”
android:layout_rowWeight=”1”
android:visibility=”visible”
>

<ImageView
android:id=”@+id/imageView5”
android:layout_width=”wrap_content”
android:layout_height=”@dimen/biao_discover_item_iv_height”
android:src=”@drawable/ic_found_room_search”
android:layout_centerVertical=”true”
android:layout_centerHorizontal=”true”/>

<TextView
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_below=”@+id/imageView5”
android:layout_centerHorizontal=”true”
android:layout_marginTop=”@dimen/biao_discover_item_tv_margin_top”
android:text=”@string/biao_classroom_search”
android:textColor=”@color/gray2”
android:textSize=”@dimen/biao_discover_item_tv_text_size”/>
</com.zhy.autolayout.AutoRelativeLayout>

<com.zhy.autolayout.AutoRelativeLayout
android:id=”@+id/rll_found_score_search”
android:layout_width=”wrap_content”
android:layout_column=”0”
android:layout_columnWeight=”1”
android:layout_row=”1”
android:layout_rowWeight=”1”
android:visibility=”visible”
>

<ImageView
android:id=”@+id/imageView6”
android:layout_width=”wrap_content”
android:layout_height=”@dimen/biao_discover_item_iv_height”
android:src=”@drawable/ic_found_score_search”
android:layout_centerVertical=”true”
android:layout_centerHorizontal=”true”/>

<TextView
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_below=”@+id/imageView6”
android:layout_centerHorizontal=”true”
android:layout_marginTop=”@dimen/biao_discover_item_tv_margin_top”
android:text=”@string/biao_score_search”
android:textColor=”@color/gray2”
android:textSize=”@dimen/biao_discover_item_tv_text_size”/>
</com.zhy.autolayout.AutoRelativeLayout>

<com.zhy.autolayout.AutoRelativeLayout
android:id=”@+id/rll_found_super_act”
android:layout_width=”wrap_content”
android:layout_column=”1”
android:layout_columnWeight=”1”
android:layout_row=”1”
android:layout_rowWeight=”1”
android:visibility=”visible”
>

<ImageView
android:id=”@+id/imageView7”
android:layout_width=”wrap_content”
android:layout_height=”@dimen/biao_discover_item_iv_height”
android:src=”@drawable/ic_found_super_act”
android:layout_centerVertical=”true”
android:layout_centerHorizontal=”true”/>

<TextView
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_below=”@+id/imageView7”
android:layout_centerHorizontal=”true”
android:layout_marginTop=”@dimen/biao_discover_item_tv_margin_top”
android:text=”@string/biao_super_act”
android:textColor=”@color/gray2”
android:textSize=”@dimen/biao_discover_item_tv_text_size”/>
</com.zhy.autolayout.AutoRelativeLayout>

<com.zhy.autolayout.AutoRelativeLayout
android:id=”@+id/rll_found_super_group”
android:layout_width=”wrap_content”
android:layout_column=”2”
android:layout_columnWeight=”1”
android:layout_row=”1”
android:layout_rowWeight=”1”
android:visibility=”visible”
>

<ImageView
android:id=”@+id/imageView8”
android:layout_width=”wrap_content”
android:layout_height=”@dimen/biao_discover_item_iv_height”
android:src=”@drawable/ic_found_super_group”
android:layout_centerVertical=”true”
android:layout_centerHorizontal=”true”/>

<TextView
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_below=”@+id/imageView8”
android:layout_centerHorizontal=”true”
android:layout_marginTop=”@dimen/biao_discover_item_tv_margin_top”
android:text=”@string/biao_super_group”
android:textColor=”@color/gray2”
android:textSize=”@dimen/biao_discover_item_tv_text_size”/>
</com.zhy.autolayout.AutoRelativeLayout>

<com.zhy.autolayout.AutoRelativeLayout
android:id=”@+id/rll_found_train_tickets”
android:layout_width=”wrap_content”
android:layout_column=”0”
android:layout_columnWeight=”1”
android:layout_row=”2”
android:layout_rowWeight=”1”
android:visibility=”visible”
>

<ImageView
android:id=”@+id/imageView9”
android:layout_width=”wrap_content”
android:layout_height=”@dimen/biao_discover_item_iv_height”
android:src=”@drawable/ic_found_bus”
android:layout_centerVertical=”true”
android:layout_centerHorizontal=”true”/>

<TextView
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_below=”@+id/imageView9”
android:layout_centerHorizontal=”true”
android:layout_marginTop=”@dimen/biao_discover_item_tv_margin_top”
android:text=”@string/biao_train_bus_tickets”
android:textColor=”@color/gray2”
android:textSize=”@dimen/biao_discover_item_tv_text_size”/>
</com.zhy.autolayout.AutoRelativeLayout>

<com.zhy.autolayout.AutoRelativeLayout
android:id=”@+id/rll_found_air_tickets”
android:layout_width=”wrap_content”
android:layout_column=”1”
android:layout_columnWeight=”1”
android:layout_row=”2”
android:layout_rowWeight=”1”
android:visibility=”visible”
>

<ImageView
android:id=”@+id/imageView10”
android:layout_width=”wrap_content”
android:layout_height=”@dimen/biao_discover_item_iv_height”
android:src=”@drawable/ic_found_airplane”
android:layout_centerVertical=”true”
android:layout_centerHorizontal=”true”/>

<TextView
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_below=”@+id/imageView10”
android:layout_centerHorizontal=”true”
android:layout_marginTop=”@dimen/biao_discover_item_tv_margin_top”
android:text=”@string/biao_air_tickets”
android:textColor=”@color/gray2”
android:textSize=”@dimen/biao_discover_item_tv_text_size”/>
</com.zhy.autolayout.AutoRelativeLayout>

<com.zhy.autolayout.AutoRelativeLayout
android:id=”@+id/rll_found_school_recuit”
android:layout_width=”wrap_content”
android:layout_column=”2”
android:layout_columnWeight=”1”
android:layout_row=”2”
android:layout_rowWeight=”1”
android:visibility=”visible”
>

<ImageView
android:id=”@+id/imageView11”
android:layout_width=”wrap_content”
android:layout_height=”@dimen/biao_discover_item_iv_height”
android:src=”@drawable/ic_found_school_recuit”
android:layout_centerVertical=”true”
android:layout_centerHorizontal=”true”/>

<TextView
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_below=”@+id/imageView11”
android:layout_centerHorizontal=”true”
android:layout_marginTop=”@dimen/biao_discover_item_tv_margin_top”
android:text=”@string/biao_school_recuit”
android:textColor=”@color/gray2”
android:textSize=”@dimen/biao_discover_item_tv_text_size”/>
</com.zhy.autolayout.AutoRelativeLayout>

<com.zhy.autolayout.AutoRelativeLayout
android:id=”@+id/rll_found_house_rent”
android:layout_width=”wrap_content”
android:layout_column=”0”
android:layout_columnWeight=”1”
android:layout_row=”3”
android:layout_rowWeight=”1”
android:visibility=”visible”
>

<ImageView
android:id=”@+id/imageView12”
android:layout_width=”wrap_content”
android:layout_height=”@dimen/biao_discover_item_iv_height”
android:src=”@drawable/ic_found_rent_house”
android:layout_centerVertical=”true”
android:layout_centerHorizontal=”true”/>

<TextView
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_below=”@+id/imageView12”
android:layout_centerHorizontal=”true”
android:layout_marginTop=”@dimen/biao_discover_item_tv_margin_top”
android:text=”@string/biao_house_rent”
android:textColor=”@color/gray2”
android:textSize=”@dimen/biao_discover_item_tv_text_size”/>
</com.zhy.autolayout.AutoRelativeLayout>

<com.zhy.autolayout.AutoRelativeLayout
android:id=”@+id/rll_found_entertainment_class”
android:layout_width=”wrap_content”
android:layout_column=”1”
android:layout_columnWeight=”1”
android:layout_row=”3”
android:layout_rowWeight=”1”
android:visibility=”visible”
>

<ImageView
android:id=”@+id/imageView13”
android:layout_width=”wrap_content”
android:layout_height=”@dimen/biao_discover_item_iv_height”
android:src=”@drawable/ic_found_entertainment_class”
android:layout_centerVertical=”true”
android:layout_centerHorizontal=”true”/>

<TextView
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_below=”@+id/imageView13”
android:layout_centerHorizontal=”true”
android:layout_marginTop=”@dimen/biao_discover_item_tv_margin_top”
android:text=”@string/biao_entertainment_class”
android:textColor=”@color/gray2”
android:textSize=”@dimen/biao_discover_item_tv_text_size”/>
</com.zhy.autolayout.AutoRelativeLayout>
</GridLayout>
</com.zhy.autolayout.AutoRelativeLayout>

<ImageView
android:id=”@+id/ivBiaoClose”
android:layout_width=”90dp”
android:layout_height=”wrap_content”
android:layout_alignParentBottom=”true”
android:layout_centerHorizontal=”true”
android:adjustViewBounds=”true”
android:src=”@drawable/selector_found_close_btn”/>
</com.zhy.autolayout.AutoRelativeLayout>

这个宫格布局的实现方法不是唯一的,但以上实现方法可以保证95%以上的相似,以上用到的所有图标资源请自行搜索

下面是实现后的效果




需要注意的是,布局中的图标应避免处于父布局的边缘位置,因为执行动画过程中,尤其是缩放动画,超出父布局的部分不会显示

图标的缩放动画在同样在XML文件中进行定义,这里用到了两个缩放动画,可以设置第二个动画开始时间偏移量为第一个动画的时长,这样可以使最终效果非常自然、连贯,此处加入一个透明度渐变动画,和原版更为贴近


<?xml version=”1.0” encoding=”utf-8”?>
<set xmlns:android=”http://schemas.android.com/apk/res/android">
<scale
android:duration=”75”
android:fromXScale=”0.5”
android:fromYScale=”0.5”
android:interpolator=”@android:anim/decelerate_interpolator”
android:pivotX=”50%”
android:pivotY=”50%”
android:startOffset=”0”
android:toXScale=”1”
android:toYScale=”1”/>
<scale
android:duration=”75”
android:fromXScale=”1.2”
android:fromYScale=”1.2”
android:interpolator=”@android:anim/decelerate_interpolator”
android:pivotX=”50%”
android:pivotY=”50%”
android:startOffset=”75”
android:toXScale=”1”
android:toYScale=”1”/>

<alpha
android:duration=”100”
android:fromAlpha=”0”
android:toAlpha=”1”/>
</set>

底部的关闭按钮用selector的形式定义,实现点击的效果


<?xml version=”1.0” encoding=”utf-8”?>
<selector xmlns:android=”http://schemas.android.com/apk/res/android">
<item android:drawable=”@drawable/ic_found_close_press” android:state_pressed=”true”/>
<item android:drawable=”@drawable/ic_found_close” android:state_enabled=”false”/>
</selector>





分享到: